package model;

import java.util.Random;

/**
 * A Ghost character. Its main purpose in Turn-Based Pacman 
 * is to select and chase another Character type around the Maze. 
 * 
 * @author Alex Dinardo, Alexander Craig
 */
public class Ghost extends Character
{
	/** the movePreference identifier to make the ghost favour horizontal movement */
	public static final int HORIZONTAL = 0;
	/** the movePreference identifier to make the ghost favour vertical movement */
	public static final int VERTICAL = 1;
	/** the movePreference identifier to make the ghost select randomly from valid moves */
	public static final int RANDOM = 2;
	
	/** the maximum number of times a ghost will try to find a valid move before failing */
	private static final int MAX_MOVE_ATTEMPTS = 3;
	/** The Character that the ghost is meant to chase. */
	private Character target;
	/** determines what direction the ghost will attempt to move when 2 moves are equally close to the target */
	private int movePreference;
	
	/**
	 * Constructor for objects of type Ghost.
	 * Creates a new Ghost type character.
	 * movePreference defaults to favour vertical movement.
	 * @param startTile The tile that the ghost is placed in at the start of every level. 
	 * 					It is passed the constructor of the superclass Character.
	 * @param target	The Character that the ghost is meant to chase.
	 */
	public Ghost(Tile startTile, Character target)
	{
		this(startTile, target, VERTICAL);
	}
	
	/**
	 * Constructor for objects of type Ghost.
	 * Creates a new Ghost type character.
	 * @param startTile The tile that the ghost is placed in at the start of every level. 
	 * 					It is passed the constructor of the superclass Character.
	 * @param target	The Character that the ghost is meant to chase.
	 * @param movePreference	determines what direction of movement the ghost favours.
	 * 					Note: defaults to vertical if an invalid integer is passed.
	 */
	public Ghost(Tile startTile, Character target, int movePreference)
	{
		super(startTile);
		this.target = target;
		this.movePreference = movePreference;
	}
	
	/**
	 * @return	the identifier for the ghost's movement characteristics
	 */
	public int getMovePreference() {
		return this.movePreference;
	}
	
	/**
	 * Determines the tile that the ghost should move to next.
	 * @return 	the adjacent tile in the direction the ghost should move in, or null if no
	 * 			move should be made
	 */
	public Tile getNextMove()
	{
		if (target == null)
			return null;
		
		// Stores the orientation the ghost should try to move in.
		// True for horizontal, false for vertical
		boolean horVer;
		Tile moveTile = null;
		int x = target.getTile().getXCoord() - this.getTile().getXCoord();
		int y = target.getTile().getYCoord() - this.getTile().getYCoord();
		
		if (Math.abs(x) > Math.abs(y)) {
			horVer = true;
		} else if ( Math.abs(y) > Math.abs(x)) {
			horVer = false;
		} else {
			
			// This code determines what happens when the player is perfectly
			// diagonal to the ghost.
			// Note: It was decided that subclasses were unnecessary for this simple behaviour
			// Defaults to vertical if an invalid value is set
			
			if(movePreference == RANDOM) {
				Random rand = new Random();
				horVer = rand.nextBoolean();
			} else if (movePreference == HORIZONTAL) {
				horVer = true;
			} else {
				horVer = false;
			}
		}
		
		int attempts = 1;
		while (attempts <= MAX_MOVE_ATTEMPTS) {
			if (horVer) {
				if (x > 0) {
					moveTile = getNeighbour(Direction.EAST);
					setLastMove(Direction.EAST);
				} else if (x < 0) {
					moveTile = getNeighbour(Direction.WEST);
					setLastMove(Direction.WEST);
				}
			} else {
				if (y < 0) {
					moveTile = getNeighbour(Direction.NORTH);
					setLastMove(Direction.NORTH);
				} else if (y > 0) {
					moveTile = getNeighbour(Direction.SOUTH);
					setLastMove(Direction.SOUTH);
				}
			}
			
			if (moveTile == null) {
				setLastMove(null);
				attempts++;
				horVer = !horVer;
			} else {
				break;
			}
		}
		
		return moveTile;
	}
}
